package com.siyoumi.app.modules.app_fks.service;

import com.siyoumi.annotation.RequestLimit;
import com.siyoumi.app.entity.*;
import com.siyoumi.app.modules.app_fks.vo.*;
import com.siyoumi.app.modules.fun.service.SvcFun;
import com.siyoumi.app.modules.redbook.service.SvcRedbookQuan;
import com.siyoumi.app.modules.redbook.vo.VaRedBookQuan;
import com.siyoumi.app.service.FksFileAuthService;
import com.siyoumi.app.service.FksFileService;
import com.siyoumi.component.XApp;
import com.siyoumi.component.XBean;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.config.SysConfig;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.mybatispuls.JoinWrapperPlus;
import com.siyoumi.service.IWebService;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XStr;
import com.siyoumi.validator.XValidator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

//文件
@Slf4j
@Service
public class SvcFksFile
        implements IWebService {
    static public SvcFksFile getBean() {
        return XSpringContext.getBean(SvcFksFile.class);
    }

    static public FksFileService getApp() {
        return FksFileService.getBean();
    }

    public Boolean isNote(FksFile entity) {
        return "note".equals(entity.getFfile_file_ext());
    }

    public boolean existsAuth(String fileId, String uid) {
        JoinWrapperPlus<FksFileAuth> query = listAuthQuery(fileId);
        query.eq("ffauth_type_id", uid);
        query.select("1");
        Map<String, Object> entity = FksFileAuthService.getBean().firstMap(query);
        return entity != null;
    }

    /**
     * 权限
     *
     * @param entityFile
     * @param entityUser
     */
    public XReturn auth(FksFile entityFile, FksUser entityUser, Boolean look) {
        //权限判断
        if (entityFile.getFfile_uid().equals(getUid())) {
            return EnumSys.OK.getR();
        }

        Integer positionLevel = SvcFksPosition.getBean().getPositionLevel(entityUser.getFuser_position_id());
        if (positionLevel == 0) { //顶级
            return EnumSys.OK.getR();
        }

        if (look) {
            if (existsAuth(entityFile.getKey(), entityUser.getKey())) { //有配置权限
                return EnumSys.OK.getR();
            }
        }

        return XReturn.getR(20076, "操作失败，权限不足");
    }

    static public List<String> fileAccept() {
        List<String> list = new ArrayList<>();
        //list.add(".mp4");
        if (SysConfig.getBean().isDev()) {
            list.add(".jpg");
        }
        //list.add(".png");
        list.add(".txt");
        list.add(".pdf");
        list.add(".doc");
        list.add(".docx");
        list.add(".xls");
        list.add(".xlsx");
        return list;
    }

    /**
     * 文件大小显示
     *
     * @param size
     */
    static public String fileSize(Long size) {
        if (size <= 0) {
            return "";
        }

        if (size < 1024) {
            return size + "B";
        } else if (size < 1024 * 1024) {
            return BigDecimal.valueOf(size).divide(BigDecimal.valueOf(1024), 1, RoundingMode.DOWN) + "KB";
        }

        return BigDecimal.valueOf(size).divide(BigDecimal.valueOf(1024 * 1024), 1, RoundingMode.DOWN) + "MB";
    }

    public JoinWrapperPlus<FksFile> listQuery(Integer type, String folderId, String typeId) {
        InputData inputData = InputData.getIns();
        inputData.put("folder_id", folderId);
        inputData.put("type_id", typeId);
        return listQuery(type, inputData);
    }

    public JoinWrapperPlus<FksFile> listQuery(Integer type) {
        return listQuery(type, InputData.getIns());
    }

    /**
     * select
     *
     * @return query
     */
    public JoinWrapperPlus<FksFile> listQuery(Integer type, InputData inputData) {
        String name = inputData.input("name");
        String folderId = inputData.input("folder_id");
        String dataType = inputData.input("data_type");
        String typeId = inputData.input("type_id");
        String fileExt = inputData.input("file_ext");

        JoinWrapperPlus<FksFile> query = getApp().join();
        query.eq("ffile_x_id", XHttpContext.getX())
                .eq("ffile_type", type)
                .eq("ffile_del", 0);
        if (XStr.hasAnyText(folderId)) { //文件夹
            query.eq("ffile_folder_id", folderId);
        } else {
            query.eq("ffile_folder_id", "");
        }
        if (XStr.hasAnyText(typeId)) { //类型ID
            query.eq("ffile_type_id", typeId);
        } else {
            query.eq("ffile_type_id", "");
        }
        if (XStr.hasAnyText(dataType)) { //数据分类
            query.eq("ffile_data_type", dataType);
        }
        if (XStr.hasAnyText(fileExt)) { //后缀
            query.eq("ffile_file_ext", fileExt);
        }
        if (XStr.hasAnyText(name)) { //名称
            query.like("ffile_name", name);
        }

        return query;
    }

    public JoinWrapperPlus<FksFileAuth> listAuthQuery(String fileId) {
        return listAuthQuery(fileId, 0);
    }

    public JoinWrapperPlus<FksFileAuth> listAuthQuery(String fileId, Integer type) {
        JoinWrapperPlus<FksFileAuth> query = FksFileAuthService.getBean().join();
        query.eq("ffauth_file_id", fileId)
                .eq("ffauth_type", type);

        return query;
    }

    public XReturn edit(InputData inputData, VaFksDataFile vo) {
        List<String> ignoreField = new ArrayList<>();
        if (inputData.isAdminEdit()) {
            ignoreField.add("ffile_acc_id");
            ignoreField.add("ffile_uid");
            ignoreField.add("ffile_data_type");
            ignoreField.add("ffile_type");
            ignoreField.add("ffile_type_id");
            ignoreField.add("ffile_folder");
        }

        return XApp.getTransaction().execute(status -> {
            XReturn r = getApp().saveEntity(inputData, vo, false, ignoreField);
            XValidator.err(r);
            FksFile entity = r.getData("entity");
            if (vo.getFfile_auth() == 1 && vo.getAuth_set() == 1) {
                //删除关系
                delAuthUser(entity.getKey());

                //添加权限
                List<FksFileAuth> list = new ArrayList<>();
                for (String uid : vo.getAuth_uids()) {
                    FksFileAuth entityAuthUser = new FksFileAuth();
                    entityAuthUser.setFfauth_x_id(XHttpContext.getX());
                    entityAuthUser.setFfauth_file_id(entity.getKey());
                    entityAuthUser.setFfauth_type(0);
                    entityAuthUser.setFfauth_type_id(uid);
                    entityAuthUser.setAutoID();

                    list.add(entityAuthUser);
                }
                FksFileAuthService.getBean().saveBatch(list);
            }

            return r;
        });
    }

    /**
     * 删除标签ID所有关系
     *
     * @param fileId
     */
    public XReturn delAuthUser(String fileId) {
        JoinWrapperPlus<FksFileAuth> query = listAuthQuery(fileId);
        List<FksFileAuth> list = FksFileAuthService.getBean().get(query);
        if (list.size() > 0) {
            List<String> ids = list.stream().map(item -> item.getKey()).collect(Collectors.toList());
            FksFileAuthService.getBean().delete(ids);
        }
        return EnumSys.OK.getR();
    }

    /**
     * 删除
     */
    @SneakyThrows
    @Transactional(propagation = Propagation.MANDATORY)
    public XReturn delete(List<String> ids) {
        XReturn r = XReturn.getR(0);

        getApp().delete(ids);

        return r;
    }

    public XReturn fileDel(FksFileDel vo) {
        FksUser entityUser = SvcFksUser.getBean().getEntity(getUid());

        List<FksFile> listFile = SvcFksFile.getApp().get(vo.getFile_ids());
        for (FksFile entityFile : listFile) {
            //if (entityFile.getFfile_type() != 1) {
            //    return EnumSys.ERR_VAL.getR(entityFile.getFfile_name() + ": 文件类型异常");
            //}

            XReturn r = FksFileAuthHandle.of("del").handle(FksFileAuthHandleData.of(entityFile, entityUser));
            if (r.err()) {
                r.setErrMsg(entityFile.getFfile_name(), ": ", r.getErrMsg());
                return r;
            }
        }

        return XApp.getTransaction().execute(status -> {
            SvcFksFile.getBean().delete(listFile.stream().map(item -> item.getKey()).collect(Collectors.toList()));

            List<String> uids = new ArrayList<>();
            for (FksFile entityFile : listFile) {
                if ("note".equals(entityFile.getFfile_file_ext())) {
                    //笔记需要删除quan
                    SvcRedbookQuan.getBean().delete(List.of(entityFile.getFfile_note_id()), null);

                    uids.add(entityFile.getFfile_uid());
                }
            }

            //更新用户笔记数量
            List<String> uidsDist = uids.stream().distinct().collect(Collectors.toList());
            for (String uid : uidsDist) {
                SvcFksUser.getBean().updateNoteCount(uid);
            }

            return EnumSys.OK.getR();
        });
    }

    /**
     * 重命名文件
     *
     * @param vo
     */
    public XReturn fileRename(FksFileRename vo) {
        FksFile entity = SvcFksFile.getApp().getEntity(vo.getFile_id());
        if (entity == null) {
            return EnumSys.ERR_VAL.getR("文件ID异常");
        }
        if (SvcFksFile.getBean().isNote(entity)) {
            return EnumSys.ERR_VAL.getR("笔记不能重命名");
        }

        FksUser entityUser = SvcFksUser.getBean().getEntity(getUid());
        XReturn r = FksFileAuthHandle.of("rename").handle(FksFileAuthHandleData.of(entity, entityUser));
        if (r.err()) {
            r.setErrMsg(entity.getFfile_name(), ": ", r.getErrMsg());
            return r;
        }

        //检查文件名是否存在
        {
            JoinWrapperPlus<FksFile> query = listQuery(entity.getFfile_type(), entity.getFfile_folder_id(), entity.getFfile_type_id());
            query.eq("ffile_name", vo.getFile_name())
                    .eq("ffile_file_ext", entity.getFfile_file_ext())
                    .ne("ffile_id", vo.getFile_id());
            FksFile entityFile = getApp().first(query);
            if (entityFile != null) {
                return EnumSys.ERR_VAL.getR("文件名已存在");
            }
        }


        FksFile entityUpdate = new FksFile();
        entityUpdate.setFfile_id(entity.getFfile_id());
        entityUpdate.setFfile_name(vo.getFile_name());
        getApp().saveOrUpdatePassEqualField(entity, entityUpdate);

        return EnumSys.OK.getR();
    }

    /**
     * 移动文件
     *
     * @param vo
     */
    public XReturn fileMove(FksFileMove vo) {
        if (XStr.hasAnyText(vo.getFolder_id())) {
            FksFile entityFolder = getApp().loadEntity(vo.getFolder_id());
            if (entityFolder.getFfile_folder() != 1) {
                return EnumSys.ERR_VAL.getR("文件夹ID异常");
            }
        }

        FksUser entityUser = SvcFksUser.getBean().getEntity(getUid());

        List<String> fileIds = List.of(vo.getFile_ids().split(","));
        List<FksFile> listFile = SvcFksFile.getApp().get(fileIds);
        for (FksFile entityFile : listFile) {
            //if (entityFile.getFfile_type() != 1) {
            //    return EnumSys.ERR_VAL.getR(entityFile.getFfile_name() + ": 文件类型异常");
            //}
            //if (entityFile.getFfile_folder() == 1) {
            //    return EnumSys.ERR_VAL.getR(entityFile.getFfile_name() + ": 文件夹不能移动");
            //}

            XReturn r = FksFileAuthHandle.of("move").handle(FksFileAuthHandleData.of(entityFile, entityUser));
            if (r.err()) {
                r.setErrMsg(entityFile.getFfile_name(), ": ", r.getErrMsg());
                return r;
            }
        }

        return XApp.getTransaction().execute(status -> {
            for (FksFile entityFile : listFile) {
                FksFile entityFileUpdate = new FksFile();
                entityFileUpdate.setFfile_id(entityFile.getFfile_id());
                entityFileUpdate.setFfile_folder_id(vo.getFolder_id());
                if (XStr.isNullOrEmpty(vo.getFolder_id())) {
                    entityFileUpdate.setFfile_folder_id("");
                }

                getApp().saveOrUpdatePassEqualField(entityFile, entityFileUpdate);
            }

            return EnumSys.OK.getR();
        });
    }

    /**
     * 批量添加文件
     *
     * @param vo
     */
    public XReturn fileAdd(FksFileAddBatch vo) {
        if (vo.getAuth() == 1) {
            if (vo.getAuth_uids() == null || vo.getAuth_uids().size() <= 0) {
                return EnumSys.ERR_VAL.getR("缺少权限用户");
            }
        }
        if (vo.getType() == 1) {
            List<String> typeIds = List.of("common", "department", "person", "note");
            if (!typeIds.contains(vo.getType_id())) {
                return EnumSys.ERR_VAL.getR("共享空间请输入指定值，" + typeIds.toString());
            }
        } else {
            XValidator.isNullOrEmpty(vo.getData_type(), "miss data_type");
            List<String> dataType = List.of("room", "proj", "ecology", "city", "people");
            if (!dataType.contains(vo.getData_type())) {
                return EnumSys.ERR_VAL.getR("核心数据分类请输入指定值，" + dataType.toString());
            }
            FksCity entityCity = SvcFksCtiy.getApp().getEntity(vo.getType_id());
            XValidator.isNull(entityCity, "城市ID异常");
        }

        for (FksFileAdd fileItem : vo.getFile_list()) {
            if (fileItem.getFfile_folder() != 1) {
                if (XStr.isNullOrEmpty(fileItem.getFfile_file_ext())) {
                    return EnumSys.MISS_VAL.getR(fileItem.getFfile_name() + "：缺少文件类型");
                }

                if ("note".equals(fileItem.getFfile_file_ext())) {
                    if (XStr.isNullOrEmpty(fileItem.getRquan_content())) {
                        return EnumSys.MISS_VAL.getR("请输入内容");
                    }
                    if (XStr.isNullOrEmpty(fileItem.getRquan_url())) {
                        return EnumSys.MISS_VAL.getR("请上传图片");
                    }
                    if (!SysConfig.getBean().isDev()) {
                        if (vo.getFile_list().size() > 1) {
                            return EnumSys.ERR_VAL.getR("笔记不能批量创建");
                        }
                    }
                    if (vo.getType() == 2) {
                        return EnumSys.ERR_VAL.getR("核心数据不能添加笔记");
                    }
                } else {
                    if (XStr.isNullOrEmpty(fileItem.getFfile_path())) {
                        return EnumSys.MISS_VAL.getR(fileItem.getFfile_name() + "：缺少文件原路径");
                    }
                    if (XStr.isNullOrEmpty(fileItem.getFfile_file_url())) {
                        return EnumSys.MISS_VAL.getR(fileItem.getFfile_name() + "：缺少文件访问路径");
                    }
                    if (fileItem.getFfile_file_size() == null) {
                        return EnumSys.MISS_VAL.getR(fileItem.getFfile_name() + "：缺少文件大小");
                    }
                }
            } else {
                if (vo.getFile_list().size() > 1) {
                    return EnumSys.MISS_VAL.getR("目录不能批量创建");
                }
            }
        }
        //
        vo.setUid(getUid());
        //
        FksUser entityUser = SvcFksUser.getApp().loadEntity(getUid());
        //保存文件
        return XApp.getTransaction().execute(status -> {
            boolean isNote = false;

            List<FksFile> fileList = new ArrayList<>();
            for (FksFileAdd fileItem : vo.getFile_list()) {
                if ("note".equals(fileItem.getFfile_file_ext())) {
                    isNote = true;

                    //笔记，添加redbook
                    VaRedBookQuan vaRedBookQuan = new VaRedBookQuan();
                    vaRedBookQuan.setRquan_app_id("app_fks");
                    vaRedBookQuan.setRquan_uid(vo.getUid());
                    vaRedBookQuan.setRquan_title(fileItem.getFfile_name());
                    vaRedBookQuan.setRquan_content(fileItem.getRquan_content());
                    vaRedBookQuan.setRquan_type(0);
                    vaRedBookQuan.setRquan_url(fileItem.getRquan_url());

                    InputData inputData = InputData.getIns();
                    XReturn rr = SvcRedbookQuan.getApp().saveEntity(inputData, vaRedBookQuan, true, null);
                    XValidator.err(rr);

                    RedbookQuan entityQuan = rr.getData("entity");
                    fileItem.setFfile_note_id(entityQuan.getRquan_id());
                    vo.setType_id("note"); //笔记只能放在笔记空间
                }

                VaFksDataFile vaFile = new VaFksDataFile();
                XBean.copyProperties(fileItem, vaFile);
                vaFile.setFfile_type(vo.getType());
                vaFile.setFfile_data_type(vo.getData_type());
                vaFile.setFfile_uid(vo.getUid());
                vaFile.setFfile_type_id(vo.getType_id());
                vaFile.setFfile_department_id(entityUser.getFuser_department_id());
                vaFile.setFfile_auth(vo.getAuth());
                vaFile.setAuth_uids(vo.getAuth_uids());
                vaFile.setAuth_set(1);

                InputData inputData = InputData.getIns();
                XReturn r = SvcFksFile.getBean().edit(inputData, vaFile);
                XValidator.err(r);
                FksFile entity = r.getData("entity");

                fileList.add(entity);
            }

            if (isNote) {
                //更新笔记数量
                SvcFksUser.getBean().updateNoteCount(getUid());
            }

            XReturn r = EnumSys.OK.getR();
            r.setData("file_list", fileList);
            return r;
        });
    }
}
